package com.jicheng.controller;

import com.jicheng.Utils.*;
import com.jicheng.constants.Constants;
import com.jicheng.constants.RedisKey;
import com.jicheng.dto.account.LoginParams;
import com.jicheng.dto.account.VerifyCodeDto;
import com.jicheng.dto.sysUser.UserInfo;
import com.jicheng.entity.SysLog;
import com.jicheng.mapper.SysLogMapper;
import com.jicheng.service.SysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * @ClassName: LoginController
 * @Description: TODO
 * @author: khz
 * @date: 2020年09月16日 15:38
 */
@Api(tags = "用户登录")
@RestController
public class LoginController {
    private Logger log = LoggerFactory.getLogger(VerifyCodeCheck.class);
    @Autowired
    SysUserService sysUserService;
    @Resource
    VerifyCodeCheck verifyCodeCheck;
    @Resource
    RedisUtils redisUtils;

    @Autowired
    SysLogMapper sysLogMapper;
    @ApiOperation(value = "登录")
    @PostMapping("/login")
    public ResultMess login(@RequestBody LoginParams loginParams) {

        boolean res = verifyCodeCheck.checkVerifyCode(loginParams.getVerifyCode(), loginParams.getCode());
        if (!res) {
            return new ResultMess(false, "验证码错误！", null);
        }

        //数据库加密的密码
        String realPassword = sysUserService.getPassword(loginParams.getUsername());
        //对用户密码加密与数据库加密密码进行对比
        String encryption = MD5Util.shiroEncryption(loginParams.getPassword());
        if (realPassword == null) {
            return new ResultMess(false, "用户名错误", null);
        } else if (!realPassword.equals(encryption)) {
            return new ResultMess(false, "密码错误", null);
        } else {
            //获取用户信息
            UserInfo userInfo = sysUserService.getUserInfo(loginParams.getUsername());
            String token = JWTUtil.createToken(loginParams.getUsername());
            Map map = new HashMap();
            map.put("token",token );
            map.put("userInfo", userInfo);
            //登录成功往保存登录日志
            SysLog sysLog = new SysLog();
            sysLog.setUserName(loginParams.getUsername());
            sysLog.setStartLoginTime(new Date());
            sysLog.setEndLoginTime((new Date(new Date().getTime()+60 * 1 * 60 * 1000)));
            sysLog.setOnlineTime("60分钟");
            sysLog.setToken(token);
            sysLogMapper.insertSelective(sysLog);
            return new ResultMess(true, "登录成功", map);
        }
    }

    @ApiOperation(value = "非法登录提示")
    @GetMapping(path = "/unauthorized/{message}")
    public void unauthorized(@PathVariable String message) {
        throw new AuthenticationException(message);

    }

    @ApiOperation(value = "登出操作")
    @GetMapping(path = "/logout")
    public ResultMess logout(ServletRequest request, ServletResponse response) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        //拿到token放到Redis黑名单,设置清理时间
        String token = httpServletRequest.getHeader("Token");
        if (token != null && !token.equals("")) {
            try {
                redisUtils.set(token, token, Constants.EXPIRE_TIME);
                //根据token获取当前操作日志，更改累计在线时间，退出时间
              SysLog sysLog =   sysLogMapper.getLog(token);
              sysLog.setOnlineTime(String.valueOf((System.currentTimeMillis()-sysLog.getStartLoginTime().getTime())/(60*1000))+"分钟");
              sysLog.setEndLoginTime(new Date());
              sysLogMapper.updateSysLog(token,sysLog);
                return new ResultMess(true, "退出成功！", null);
            } catch (Exception e) {
                e.printStackTrace();
                return new ResultMess(false, "退出失败！" + e.getMessage(), null);
            }
        }
        log.info("请求中不能token为空！退出失败");
        return new ResultMess(false, "请求中不能token为空！退出失败", null);
    }


    @ApiOperation(value = "获取验证码")
    @GetMapping("/getVerifyCode")
    public ResultMess<VerifyCodeDto> getVerifyCode() {
        final String stringRandom = VerifyCodeUtils.getStringRandom(4);
        try {
            final String s = VerifyCodeUtils.imageToBase64(120, 40, stringRandom);
            String l = RandomStringUtils.random(10, true, true);
            redisUtils.set(RedisKey.KEY_VERIFY_CODE + l, stringRandom, 1000);//存储
            final VerifyCodeDto verifyCodeDto = new VerifyCodeDto(l, s, stringRandom);
            log.info("Key: {}, code: {}", l, stringRandom);
            return new ResultMess(true, "获取验证码成功", verifyCodeDto);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultMess(true, e.getMessage());
        }
    }

    @ApiOperation(value = "app获取token")
    @PostMapping("/getToken")
    public ResultMess getToken(@RequestParam("username") @ApiParam("用户名") String username,
                               @RequestParam("password") @ApiParam("密码") String password) {

        String realPassword = sysUserService.getPassword(username);
        String encryption = MD5Util.shiroEncryption(password);
        if (realPassword == null) {
            return new ResultMess(false, "用户名错误", null);
        } else if (!realPassword.equals(encryption)) {
            return new ResultMess(false, "密码错误", null);
        } else {
            Map token = new HashMap();
            token.put("token", JWTUtil.createToken(username));
            return new ResultMess(true, "登录成功", token);
        }
    }

    /**
     * 这个方法跟JWTFiler的isAccessAllowed方法搭配用，由于过滤器里面抛出异常全局异常只能抓取Contrellor里面的，
     * 当用户退出后再用这个token登录时抛出认证异常，返回到客户端
     */
    @GetMapping("/rethrow")
    public void rethrow() {
        throw new AuthenticationException();

    }

}
